﻿#include <cmath>
#include <QMessageBox>
#include "kcalculatorcontroller.h"

//初始化控制器，绑定 view/input/model 并连接信号槽
CalculatorController::CalculatorController(DisplayView* view,
    InputHandler* input,
    Calculator* model,
    QObject* parent)
    : QObject(parent),
    m_pview(view),
    m_pinputHandler(input),
    m_pmodel(model)
{
    m_pinputHandler->attachButtons(m_pview->allButtons());

    connect(m_pinputHandler, &InputHandler::digitButtonPressed, this, &CalculatorController::onDigit);
    connect(m_pinputHandler, &InputHandler::operatorButtonPressed, this, &CalculatorController::onOperator);
    connect(m_pinputHandler, &InputHandler::parenthesisButtonPressed, this, &CalculatorController::onParenthesis);
    connect(m_pinputHandler, &InputHandler::pointButtonPressed, this, &CalculatorController::onPoint);
    connect(m_pinputHandler, &InputHandler::clearEntryButtonPressed, this, &CalculatorController::onClearEntry);
    connect(m_pinputHandler, &InputHandler::clearButtonPressed, this, &CalculatorController::onClear);
    connect(m_pinputHandler, &InputHandler::backButtonPressed, this, &CalculatorController::onBack);
    connect(m_pinputHandler, &InputHandler::equalButtonPressed, this, &CalculatorController::onEqual);
    connect(m_pinputHandler, &InputHandler::inverseButtonPressed, this, &CalculatorController::onInverse);
    connect(m_pinputHandler, &InputHandler::squareButtonPressed, this, &CalculatorController::onSquare);
    connect(m_pinputHandler, &InputHandler::sqrtButtonPressed, this, &CalculatorController::onSqrt);
    connect(m_pinputHandler, &InputHandler::percentButtonPressed, this, &CalculatorController::onRelativePercent);
    connect(m_pinputHandler, &InputHandler::deleteButtonPressed, this, &CalculatorController::onDelete);
    connect(m_pinputHandler, &InputHandler::negateButtonPressed, this, &CalculatorController::onNegate);
    connect(m_pinputHandler, &InputHandler::forwardButtonPressed, this, &CalculatorController::onForward);

    m_pview->setExpression("0");
    m_pview->setProcessExpression("0");

    connect(m_pview->historyToggleButton(), &QPushButton::clicked, m_pview->historyPopup(), &HistoryPopup::toggle);
    connect(view->historyPopup(), &HistoryPopup::historyResultClicked, this, &CalculatorController::onHistoryResultSelected);
}

//历史记录项被点击后恢复结果
void CalculatorController::onHistoryResultSelected(const QString& result) {
    m_exprBuffer.clear();
    m_exprBuffer.append(result);
    updateDisplay();
}

//获取表达式缓冲区引用
ExpressionBuffer& CalculatorController::getBuffer() {
    return m_exprBuffer;
}

//数字输入
void CalculatorController::onDigit(QChar key) {
    m_exprBuffer.append(QString(key));
    updateDisplay();
}

//运算符输入
void CalculatorController::onOperator(QChar key) {
    m_exprBuffer.append(QString(key));
    updateDisplay();
}

//括号输入
void CalculatorController::onParenthesis(QChar key) {
    m_exprBuffer.append(QString(key));
    updateDisplay();
}

//小数点输入
void CalculatorController::onPoint(QChar key) {
    m_exprBuffer.append(QString(key)); 
    updateDisplay();
}

//清除当前输入按钮
void CalculatorController::onClearEntry() {
    QString expr = m_exprBuffer.toString();
    if (expr.isEmpty()) return;

    //通过正则表达式对象，先尝试找到最后一个运算符
    int lastOpIndex = expr.lastIndexOf(QRegExp("[\\+\\-\\*/\\(\\)]"));

    //从最后一个运算符之后保留的部分是“当前输入”
    QString currentInput = expr.mid(lastOpIndex + 1);

    if (currentInput.isEmpty()) return;

    //删除最后输入的这一段
    expr.chop(currentInput.length());

    //重构表达式
    m_exprBuffer.clear();
    if (!expr.isEmpty())
        m_exprBuffer.append(expr);

    m_exprBuffer.clearMinus(); // 还原负号状态
    updateDisplay();
}


//清除表达式和历史
void CalculatorController::onClear() {
    m_exprBuffer.clear();
    m_exprBuffer.clearProcess();
    m_exprBuffer.clearMinus();
    updateDisplay();
    m_pview->setProcessExpression("0");
}

//撤销一步操作
void CalculatorController::onBack() {
    m_exprBuffer.undo();
    updateDisplay();
}

//等号点击：补全括号、计算、保存历史
void CalculatorController::onEqual() {
    //自动补全-的括号
    int minusCount = m_exprBuffer.getMinusCount();
    for (int i = 0; i < minusCount; ++i) {
        m_exprBuffer.append(")");
        onDelete(); // 删除多余括号
    }

    QString expr = m_exprBuffer.toString();
    //自动补全根号的右括号
    int left = expr.count('('), right = expr.count(')');
    while (right < left) {
        m_exprBuffer.append(")");
        ++right;
    }
    QString processExpression = m_exprBuffer.toDisplayString() + "=";
    //如果直接按等于号的处理
    if (expr.isEmpty()) processExpression = "0=";

    long double result = m_pmodel->calculate(expr);
    if (std::isnan(result)) {
        QMessageBox::warning(m_pview, "Wrong", "Invalid expression, such as division by zero or square root of a negative number!");
        return;
    }
    
    //设置过程显示
    m_pview->setProcessExpression(processExpression);
    m_exprBuffer.pushProcess();

    //把浮点数 result 转换成一个字符串
    QString resultStr = QString::number(result, 'g', 15);
    //添加信息到历史记录栏里面
    m_pview->historyPopup()->addRecord(processExpression, resultStr);

    m_exprBuffer.clear();
    m_exprBuffer.clearMinus();
    m_exprBuffer.append(resultStr);

    updateDisplay();
}

//1/x 包裹表达式
void CalculatorController::onInverse() {
    m_exprBuffer.wrapWithInverse();
    updateDisplay();
}


//百分比相对运算处理：只对最后一个数字做百分比，如 3+2+10% => 3+2+0.2
void CalculatorController::onRelativePercent() {
    QString expr = m_exprBuffer.toString();

    //找最后一个运算符，从尾部向前找最后一个运算符 + - × ÷ 的位置
    int lastOpIndex = expr.lastIndexOf(QRegExp("[\\+\\-\\*/]"));
    if (lastOpIndex == -1 || lastOpIndex == expr.length() - 1)
        return;

    //向前找 base 数字起始，向前找到 运算符前的完整数字（包括小数点）的位置
    //比如 200+10，会找到 prevNumStart = 0，prevNumEnd = 2
    //所以base是200
    int prevNumEnd = lastOpIndex - 1;
    int prevNumStart = prevNumEnd;
    while (prevNumStart >= 0 && (expr[prevNumStart].isDigit() || expr[prevNumStart] == '.'))
        --prevNumStart;
    ++prevNumStart;

    //提取 base、op、percent 部分
    //mid用于从字符串中提取子串，第几个位置开始提取多少
    QString baseExpr = expr.mid(prevNumStart, prevNumEnd - prevNumStart + 1);
    QString op = expr.mid(lastOpIndex, 1);
    QString percentExpr = expr.mid(lastOpIndex + 1);

    //计算实际百分比值
    double baseValue = m_pmodel->calculate(baseExpr);
    double percentValue = m_pmodel->calculate(percentExpr);
    double percentAmount = baseValue * percentValue / 100.0;

    //拼接完整表达式：base 之前 + base + 运算符 + 百分值
    QString prefix = expr.left(prevNumStart); // base 之前的内容
    QString resultExpr = prefix + baseExpr + op + QString::number(percentAmount, 'g', 15);

    //更新表达式
    m_exprBuffer.clear();
    m_exprBuffer.append(resultExpr);
    updateDisplay();
}


//平方符号追加
void CalculatorController::onSquare() {
    QString last = m_exprBuffer.toString().right(1);
    if (last.isEmpty() || !(last.at(0).isDigit() || last == ")")) return; //没有数字不能加平方
    m_exprBuffer.append("^2");
    updateDisplay();
}

//开根号追加sqrt(
void CalculatorController::onSqrt() {
    QString last = m_exprBuffer.toString().right(1);
    if (!last.isEmpty() && (last.at(0).isDigit() || last == ")")) return; //不允许前面是数字直接输 sqrt
    m_exprBuffer.append("sqrt(");
    updateDisplay();
}


//删除最后一字符
void CalculatorController::onDelete() {
    QString expr = m_exprBuffer.toString();
    if (!expr.isEmpty()) {
        // 整体删除特殊 token
        if (expr.endsWith("sqrt")) {
            expr.chop(5); //删除整个sqrt以及（
        }
        else if (expr.endsWith("^2")) {
            expr.chop(2); //删除整个平方
        }
        else if (expr.endsWith("pct")) {
            expr.chop(3); //删除整个百分比
        }
        else {
            expr.chop(1); //默认删除一个字符
        }
        m_exprBuffer.clear();
        if (!expr.isEmpty())
        {
            m_exprBuffer.append(expr);
        }
    }
    updateDisplay();
}

//取反包裹表达式
void CalculatorController::onNegate() {
    m_exprBuffer.wrapWithNegate();
    updateDisplay();
}

//从 redo 栈恢复表达式
void CalculatorController::onForward() {
    m_exprBuffer.redo();
    updateDisplay();
}

//更新主界面表达式显示（转换符号 √ 和 ²）
void CalculatorController::updateDisplay() {
    m_displayExpression = m_exprBuffer.toString();
    m_displayExpression.replace("^2", QChar(0x00B2));
    m_displayExpression.replace("sqrt", QStringLiteral("\u221A"));
    m_displayExpression.replace("-1*", "-");
    m_pview->setExpression(m_displayExpression.isEmpty() ? "0" : m_displayExpression);
}